package base

/**
 * Created by Darkness1m on 2017/6/11.
 */
interface IBase{
    fun print()
}
class BaseImpl(val x: Int): base.IBase {
    override fun print() {
        println(x)
    }
}
//by子句表示b将在DerivedClass中的内部存储
//并且编译器将生成转发给b的所有Base的方法
class DerivedClass(b: base.IBase): base.IBase by b

//大概意思应该是,使用委托创建的类,会去调用传入参数类相同接口下的实现方法
fun main19(args: Array<String>) {
    val b = base.BaseImpl(10)
    base.DerivedClass(b).print()//输出10
}

//属性委托
//对于属性的委托,其委托类需要提供一个getValue(和一个setValue--仅对于var而言)
class Example{
    var p: String by base.Delegate()
}
class Delegate{
    //必须使用operator修饰,参数为下列固定其中Any?必须为接受参数的类或其超类
    operator fun getValue(thisRef: Any?,property: kotlin.reflect.KProperty<*>): String{
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
    operator fun setValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name} in $thisRef.'")
    }
}

//可以这样声明
interface ReadOnlyProperty<in R, out T> {
    operator fun getValue(thisRef: R, property: kotlin.reflect.KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
    operator fun getValue(thisRef: R, property: kotlin.reflect.KProperty<*>): T
    operator fun setValue(thisRef: R, property: kotlin.reflect.KProperty<*>, value: T)
}

fun main20(args: Array<String>) {
    val e = base.Example()
    println(e.p)//调用其委托类的getValue方法
    e.p = "测试"//调用其setValue方法
}

//延迟属性Lazy
//lazy()接收一个lambda并返回一个Lazy<T>实例,返回的示例可以作为实现延迟属性的委托
//-->第一次调用get()会执行已传递给lazy()的lambda表达式并记录结果
//后续调用get()只返回记录结果
//默认lazy属性求职是同步锁的(synchronized)
//传递LazyThreadSafetyMode.PUBLICATION or LazyThreadSafetyMode.NONE
//前者多线程同时执行,没有同步锁   后者没有线程安全保证和相关开销-->执行在单线程中
val lazyValue: String by lazy/*(LazyThreadSafetyMode.PUBLICATION)*/{
    println("initialized")//只会在第一次执行
    println("base.test")//只会在第一次执行
    "Hello"
}

fun main21(args: Array<String>) {
    println(base.lazyValue)
    println(base.lazyValue)
}

//Observable
//其接受两个参数: 初始值和修改时处理程序(handler)
//当值改变时,会触发这个handler
//handler有三个参数: 被赋值的属性、旧值和新值
class UserA{
    var name: String by kotlin.properties.Delegates.observable("<no name>"/*初值*/) {/*handler*/
        prop, old, new ->
        //三个参数
        println("$old -> $new")
    }
    var age: Int by kotlin.properties.Delegates.vetoable(23) {//返回boolean,false则抛弃
        _, old, new ->
        old == new + 1
    }
}

//如果你想能够截获一个赋值并“否决”它，就使用  vetoable()  取代  observable()


fun main22(args: Array<String>) {
    val user = base.UserA()
    user.name = "first"//<no name> -> first
    user.name = "second"//first -> second
    user.age = 13//false不生效
    println("Now the age is: ${user.age}")//Now the age is: 23
    user.age = 22//生效
    println("Now the age is: ${user.age}")//Now the age is: 22
    user.age = 25//false不生效
    println("Now the age is: ${user.age}")//Now the age is: 22
}

//把属性存储在映射中
class UserB(val map: Map<String,Any?>) {//Map是只读的,没有setter方法,所以对val适用//当然也可以似乎用MutableMap类
    val name: String by map
    val age: Int by map
}

class UserC(val map: MutableMap<String,Any?>) {//MutableMap是可读写的,对var适用
    var name: String by map
}

fun main23(args: Array<String>) {
    val user = base.UserB(mapOf(
            "name" to "John Connor",
            "age" to 33
    ))
    println("The user is ${user.name} ,and he is ${user.age} years old")
    val userC = base.UserC(mutableMapOf(
            "name" to "张三"
    ))
    println("This user is ${userC.name}")

}

class UserD{
    fun isValid(): Boolean{
        return false;
    }
    fun doSomething(){}
}
//局部委托属性
fun example(computeFoo:() -> base.UserD){
    val memorizedFoo by lazy{ base.UserD() }//在这里取类型的啊..
    if(memorizedFoo.isValid())
        memorizedFoo.doSomething()
}
//原理
class MyDelegate{
    //注意返回值
    operator fun getValue(thisRef: Any?,property: kotlin.reflect.KProperty<*>): base.UserD {
        return base.UserD()
    }
    //thisRef必须为UserE的super class,注意value的类型
    operator fun setValue(thisRef: base.UserE, property: kotlin.reflect.KProperty<*>, value: base.UserD) {
        println("$value has been assigned to '${property.name} in $thisRef.'")
    }
    //这个方法只影响初值,貌似不能和上面两个方法共存
    /*operator fun provideDelegate(thisRef: Any?,property: KProperty<*>): base.UserD{
        //这里面可以作检验等
        checkUser()
        return base.UserD()
    }*/
}
class UserE{
    //返回值不用说了
    var prop: base.UserD by base.MyDelegate()
}
/*如下为编译原理
class base.C {
    var prop: Type by base.MyDelegate()
}
// 这段是由编译器生成的相应代码：
class base.C {
    // 调用“provideDelegate”来创建额外的“delegate”属性
    private val prop$delegate = base.MyDelegate().provideDelegate(this, this::prop)
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)

    // 非provideDelegate生成的代码
    private val prop$delegate = base.MyDelegate()
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}*/
